package GA.tournaments;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import GA.Binary;
import GA.ChromosomePair;
import GA.GAPlayer;
import LUDOSimulator.Helper;
import LUDOSimulator.LUDOBoard;
import LUDOSimulator.LUDOPlayer;
import LUDOSimulator.PlayerResult;
import LUDOSimulator.SemiSmartLUDOPlayer;
import LUDOSimulator.Tournament;

public class ExtendedTournament extends Tournament
{
	public static LUDOBoard board;
	private static int rounds = 100;
	private static int round = 1;
	
	public static List<ExtendedPlayerResult> playExtendedRoundWithSemi(List<LUDOPlayer> players, ArrayList<SemiSmartLUDOPlayer> evaluationPlayers)
	{
		System.out.println("Round "+round+++" started");
		long time = System.currentTimeMillis();
		
		//HashMap<LUDOPlayer, ExtendedPlayerResult> results = new HashMap<LUDOPlayer, ExtendedPlayerResult>();
		ArrayList<ExtendedPlayerResult>	results = new ArrayList<ExtendedPlayerResult>();
		
		for (LUDOPlayer currentPlayer : players)
		{
			//results.put(currentPlayer, new ExtendedPlayerResult(currentPlayer));
			results.add(new ExtendedPlayerResult(currentPlayer));
			
			board.setPlayer(currentPlayer, LUDOBoard.YELLOW);
			board.setPlayer(evaluationPlayers.get(0), LUDOBoard.RED);
			board.setPlayer(evaluationPlayers.get(1), LUDOBoard.BLUE);
			board.setPlayer(evaluationPlayers.get(2), LUDOBoard.GREEN);
			
			try
			{
				for (int i=0; i < ExtendedTournament.rounds ; i++)
				{
					board.play();
					board.kill();
					
					//results.get(currentPlayer).add(board.getPoints()[0]);
					results.get(results.size()-1).add(board.getPoints()[0]);
					
					board.reset();
					board.setPlayer(currentPlayer, LUDOBoard.YELLOW);
					board.setPlayer(evaluationPlayers.get(0), LUDOBoard.RED);
					board.setPlayer(evaluationPlayers.get(1), LUDOBoard.BLUE);
					board.setPlayer(evaluationPlayers.get(2), LUDOBoard.GREEN);
					
					if ((i%1000) == 0) 
						System.out.print(".");
				}
			}
			catch (InterruptedException e) { e.printStackTrace(); }
		}
		
		System.out.println("\nRound took "+(System.currentTimeMillis()-time)+" miliseconds");
//		Collection<ExtendedPlayerResult> result = results.values();
//		
//		List<ExtendedPlayerResult> r = new ArrayList<ExtendedPlayerResult>();
//		
//		for(ExtendedPlayerResult rr : result)
//		{
//			r.add(rr);
//		}
		
		return results;
	}
	
	public static PlayerResult evaluateBestPlayer(LUDOPlayer toEvaluate, ArrayList<SemiSmartLUDOPlayer> evaluationPlayers)
	{
		
		ExtendedPlayerResult result = new ExtendedPlayerResult(toEvaluate);
		
		board.setPlayer(toEvaluate, LUDOBoard.YELLOW);
		board.setPlayer(evaluationPlayers.get(0), LUDOBoard.RED);
		board.setPlayer(evaluationPlayers.get(1), LUDOBoard.BLUE);
		board.setPlayer(evaluationPlayers.get(2), LUDOBoard.GREEN);
		double luckFactor = 1.0;//1.5;
		try
		{
			for (int i = 0; i < ExtendedTournament.rounds*luckFactor; i++)
			{
				board.play();
				board.kill();
	
				result.add(board.getPoints()[0]);
				
				
				board.reset();
				board.setPlayer(toEvaluate, LUDOBoard.YELLOW);
				board.setPlayer(evaluationPlayers.get(0), LUDOBoard.RED);
				board.setPlayer(evaluationPlayers.get(1), LUDOBoard.BLUE);
				board.setPlayer(evaluationPlayers.get(2), LUDOBoard.GREEN);
			}
		}
		catch (InterruptedException e) { e.printStackTrace(); }
		
		return result;
	}
	
	private static int playerID = -1;
	private static HashMap< Integer,ArrayList<int[]> > values = new HashMap<Integer, ArrayList<int[]>>();
	public static int players = 50;
	
	
	public static void signMeUp(APlayer player)
	{
		if(playerID == -1)
			loadValues();
		else if(playerID == -2 || playerID >players)
			return;

		player.actionsweight = values.get(++playerID).get(0);
		player.choices = values.get(playerID).get(1);
	}
	
	private static void loadValues()
	{
		ArrayList<int[]> returner = null;
		try 
		{
			BufferedReader br = new BufferedReader(new FileReader("genes.txt"));
			String line = br.readLine();  //priming read
			int counter = 0;
			while(line != null)
			{
				returner = new ArrayList<int[]>();
				int[] value1 = new int[ChromosomePair.actionLength];
				int[] value2 = new int[ChromosomePair.wisenessLength];
				int i = 0;
				String[] valueLine = line.split("-");
				
				for(String st : valueLine)
				{
					String[] values = st.split(",");
					for(String str : values)
					{
						if(i<ChromosomePair.actionLength)
							value1[i++] = Integer.parseInt(str);
						else
							value2[(i++)-ChromosomePair.actionLength] = Integer.parseInt(str);
					}
				}
				
				line = br.readLine();
				returner.add(value1);
				returner.add(value2);
				
				values.put(counter++, returner);
			}
			
			br.close();
			
		}
		catch (FileNotFoundException e) 
		{
			int counter = 0;
			for(int i = 0; i < players; i++)
			{
				returner = new ArrayList<int[]>();
				int[] val = new int[ChromosomePair.length];
				int[] val1 = new int[ChromosomePair.actionLength];
				int[] val2 = new int[ChromosomePair.wisenessLength];
				
				for(int j = 0; j < ChromosomePair.length; j++)
				{
					if(j < ChromosomePair.actionLength)
						val1[j] = -1;
					if(j < ChromosomePair.wisenessLength)
						val2[j] = -1;
				}
				
				for(int j = 0; j < ChromosomePair.actionLength; j++)
				{
					int test;
					do
					{
						test =(int) (Math.random()*Binary.intValue);
					}
					while(!Helper.isUnique(val1, test));
					val[j] = test;
					val1[j] = test;
				}
				for(int j = 0; j < ChromosomePair.wisenessLength; j++)
				{
					int test;
					do
					{
						test =(int) (Math.random()*Binary.intValue);
					}
					while(!Helper.isUnique(val2, test));
					val[ChromosomePair.actionLength+j] = test;
					val2[j] = test;
				}
				
				writeChromosome(val);
				returner.add(val1);
				returner.add(val2);
				values.put(counter++, returner);
			}
			
			try 
			{
				bw.flush();
				bw.close();
			} catch (IOException e1) 
			{
				e1.printStackTrace();
			}
		}
		catch (IOException ioe)
		{
			ioe.printStackTrace();
		}
		catch (NumberFormatException nfe)
		{
			nfe.printStackTrace();
		}
	}

	private static BufferedWriter bw = null;
	private static void writeChromosome(int[] val)
	{
		try 
		{
			if(bw == null)
				bw = new BufferedWriter(new FileWriter("genes.txt"));
			for(int i = 0; i < val.length; i++)
			{
				bw.append(Integer.toString(val[i])); //System.out.print(val[i]);
				if(i<ChromosomePair.actionLength-1 || (i >ChromosomePair.actionLength-1 && i< ChromosomePair.length-1))
					/*{*/bw.append(',');//System.out.print(',');}
				else if(i==ChromosomePair.actionLength-1)
					/*{*/bw.append('-');//System.out.print('-');}
			}
			bw.newLine();//System.out.println();
		} 
		catch (IOException e) 
		{
			e.printStackTrace();
		}
	}
	
	public static void writeBestChromosome(ExtendedPlayerResult plr)
	{
		try
		{
			ExtendedTournament.writeBestResult(plr);
			BufferedWriter bwr = new BufferedWriter(new FileWriter("BestPlayerChromosome.txt",true));
			GAPlayer pl = (GAPlayer) plr.getPlayer();
			
			String str = "";
			for(Binary b : pl.brain.chromosome.YChromosome)
			{
				str = str + b.getInteger()+",";
			}
			str = str.substring(0,str.length()-1)+"-";
			for(Binary b : pl.brain.chromosome.XChromosome)
			{
				str = str + b.getInteger()+",";
			}
			str = str.substring(0,str.length()-1);
			bwr.write(str+"\n");
			bwr.flush();
			bwr.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		
		
	}
	
	public static void writeAverageResult(List<ExtendedPlayerResult> results)
	{
		try
		{
			BufferedWriter bwr = new BufferedWriter(new FileWriter("AVGPlayerResult.txt",true));
			
			int first = 0;
			int second = 0;
			int third = 0;
			int fourth = 0;
			int result = 0;
			int games = results.get(0).getGames();
			int players = results.size();
			
			
			for(ExtendedPlayerResult pr : results)
			{
				first += pr.getWins();
				second += pr.getSecondPlace();
				third += pr.getThirdPlace();
				fourth += pr.getLosses();
				result += pr.getResult();
			}
			
			bwr.write(first/players+","+second/players+","+third/players+","+fourth/players+","+result/players+","+games+","+players+"\n");
			
			bwr.flush();
			bwr.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
		
	}
	
	private static void writeBestResult(ExtendedPlayerResult pl) throws IOException
	{
		BufferedWriter bwr = new BufferedWriter(new FileWriter("BestResult.txt",true));
		
		bwr.write(pl.getWins()+","+pl.getSecondPlace()+","+pl.getThirdPlace()+","+pl.getLosses()+","+pl.getResult()+","+pl.getGames()+"\n");
		
		bwr.flush();
		bwr.close();
	}
	
	public static void writeGeneration(int i, List<LUDOPlayer> l)
	{
		try
		{
			BufferedWriter bwr = new BufferedWriter(new FileWriter("Generation"+i+".txt",true));
			
			
			for(LUDOPlayer pr : l)
			{
				bwr.write(((GAPlayer)pr).toString()+"\n");
			}
			
			bwr.flush();
			bwr.close();
		}
		catch (IOException e)
		{
			e.printStackTrace();
		}
	}
}

























